/**
 * Created by zengxm on 12/16/2016.
 */
// 'use strict'
const fs=require('fs')
const _=require("underscore")
const colors=require('colors')
require('console.table')
const prompt=require('prompt')
const util=require('util')
const toI = require('./Utils').toI
const ping = require('ping')
// var Client = require('ssh2').Client
const NodeSSH=require("node-ssh")
const eachSeries=require('async').eachSeries

const FILE_NAME="./core/host.json"
const V = "1.0"

prompt.message = "[HOST]"
prompt.delimiter = " "
/**
 *
 * @param ip        主机名或者IP
 * @param port      ssh登录端口，默认22
 * @param user      登录名，默认root
 * @param pwd       登录密码
 * @param keyPath   私钥路径
 * @param des       描述
 * @constructor
 */
function Host(ip,port,user,pwd,keyPath,des) {
    if(typeof(ip) === 'object'){

    }
    this.ip = ip;
    this.port = port || 22;
    this.user = user || "root";
    this.password=pwd || null;
    this.priKey=keyPath || "";
    this.description = des ||"";
}

/**
 * 增加一个主机
 * @param h
 */
function addHostDo(h) {
    if(!h.ip) throw new Error("主机名或IP不能为空")
    if(!h.user) throw new Error("登录名不能为空")

    const hosts=getHosts()
    hosts.push(h)
    saveToFile(hosts)
}

function saveToFile(hosts) {
    //保存到文件
    fs.writeFileSync(FILE_NAME, JSON.stringify(hosts))
}

/**
 * 获取主机列表
 * @param filters       过滤条件
 * @param reverse       是否取反
 * @returns {*}
 */
function getHosts(filters,reverse) {
    //如果文件不存在
    if(!fs.existsSync(FILE_NAME))
        fs.writeFileSync(FILE_NAME,"[]");
    const json = fs.readFileSync(FILE_NAME);
    const hosts = JSON.parse(json==""?"[]":json);

    if(!filters || filters.length==0)
        return hosts
    reverse = reverse || false

    const _filter=function (e, i) {
        return _.contains(filters, ""+i) || _.contains(filters, e.ip)
    }

    if(reverse)
        return _.reject(hosts, _filter)
    else
        return _.filter(hosts, _filter)
}

function doWithHosts(filters, cb) {
    const hosts=getHosts(filters)
    if(!hosts.length)
        return console.log("未选定操作的主机（如：host ping <index || ip>）或无法匹配主机".red)
    if(typeof(cb)==='function') cb(hosts);
}

/**
 * 打印列表
 */
function printList() {
    const hosts=getHosts()
    if(hosts.length==0)
        console.log("暂无记录. 请通过 host add 命令来添加新主机".yellow)
    else {
        console.log(("共"+hosts.length+"个主机").yellow)
        const rows=[];
        for(var i=0;i<hosts.length;i++){
            const h=hosts[i];
            rows.push(['['+i+"]",h.ip,h.port,h.user,h.password,h.priKey])
        }
        console.table(['No.','IP','port','user','password','priKey'], rows);
    }
}

/**
 * 删除主机
 * @param datas
 * @param all
 * @returns {*}
 */
function del(datas, all) {
    if(!(datas.length || all)){
        return console.log("请先选定删除项（rm <index|ip>)，或者使用 -a 来删除全部".red)
    }
    prompt.confirm({description:("确定删除"+(all?"全部记录":"")+"吗？ y/n").red},(e,result)=>{
        if(result){
            if(all)
                saveToFile([])
            else
                saveToFile(getHosts(datas,true))
        }else
            console.log("HOST delete canceled...")
    })
}

//----------------------Exports-------------------------

exports.description = "主机管理.cmd 可选值：[list,add,rm]. 键入 -h 来查看更多帮助信息"
/**
 * 打印帮助信息
 */
exports.help = ()=>{
    console.log(("欢迎使用主机管理模块，主机数据保存在 "+FILE_NAME+" ，支持手动修改。").yellow);
    console.log(("注意：登录密码使用明文存在，请慎重使用！").red_bg);

    //打印信息
    let headers = ['command', 'description'];
    let rows = [
        ['list',"打印全部主机,e.g.:host list"],
        ['add','增加新主机，支持以下方式：'],
            ['','  1. add，接下来将陆续输入IP、PORT、NAME、PWD、KEY等属性'.magenta],
            ['','  2. add {IP} {PORT} {NAME} {PWD}，如: add 192.168.1.100 22 root root'.magenta],
            ['','  3. add -i {IP} -p {PORT} -w {PWD} -k {KEY_PATH}. 如：add -i 192.168.1.100 -w root'.magenta],
            ['','  （无论何种方式，IP都不能为空，如果制定了Key_Path则password属性将被忽略）'.red],
        ['rm <index>','删除特定主机,-a 则删除全部'],
        ['ping <index>','检测主机是否连通'],
        ['ssh <index>','测试SSH登录']
    ];
    console.log();
    console.table(headers, rows);

    console.log("当前版本："+V);
}

/**
 * 获取主机信息
 * @type {getHosts}
 */
exports.get=getHosts

/**
 * 处理命令
 * @param command
 * @param datas
 * @param options
 */
exports.command=(command,datas,options)=>{
    const cmd = command || "list";
    if(cmd==='list'){
        printList();
    }
    else if(cmd==='add'){
        //使用方式3进行录入
        if(options.ip){
            //暂不支持此方法，on 2016年12月20日20:38:51
            console.log("暂不支持此方法的录入，请使用 host add".red)
            process.exit(-1)
        }
        //使用方式2录入
        else if(datas.length>0){
            addHostDo({
                ip:datas.pop(),
                port:toI(datas.pop(),22),
                user:datas.pop(),
                password:datas.pop(),
                priKey:datas.pop(),
                description:datas.pop()
            });
        }
        //默认使用方式1
        else{
            prompt.get([
                {name:"ip",description:"主机名/IP",required:true,message:"主机名或IP必须填写"},
                {name:'port',type:'number'},
                {name:'user',description:"SSH登录用户名"},
                {name:'password',description:"登录密码"},
                {name:'keyPath',description:"私钥地址(无密登录)"},
                {name:'description',description:"主机描述"}
            ],(e,result)=>{
                if(e) return console.error("出错了："+e.message)
                result.port = toI(result.port, 22);

                addHostDo(result)
            })
        }
    }
    else if(cmd==='rm'){
        del(datas, options.all);
    }
    else if(cmd==='ping'){
        doWithHosts(datas,(hosts)=>{
            hosts.forEach(h=>{
                ping.sys.probe(h.ip, function (isAlive) {
                    if(isAlive) console.log((h.ip+" ping ok!").green)
                    else console.log((h.ip+" not alive for this moment...").red)
                })
            })
        })
    }
    else if(cmd==='ssh'){
        doWithHosts(datas, (hosts)=>{
            eachSeries(hosts,function (h,callBack) {
                console.log("try to log in %s@%s:%d", h.user, h.ip, h.port)
                const ssh=new NodeSSH()
                ssh.connect({
                    host: h.ip,
                    port: h.port,
                    username: h.user,
                    password: h.password
                }).then(function(){
                    console.log("\tssh %s@%s success!".green, h.user,h.ip)
                    ssh.dispose()
                    callBack()
                }, function (err) {
                    console.log("\tssh %s@%s failed:%s".red, h.user,h.ip,err.message)
                    ssh.dispose()
                    callBack(-1)
                })
            })
        })
    }
}